<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>JavaScript-变量的使用区别(JavaScript variable use difference)</title>
  <!-- 
  在 JavaScript 中，变量的定义主要通过三种关键字： `var` 、 `let`  和  `const` 。下面详细说明这三种变量定义方式的特点和使用场景。

  1.  `var` 
  - 作用域：
    -  `var`  声明的变量具有函数作用域。如果在函数外部声明，则为全局变量。
    
  - 提升：
    - 使用  `var`  声明的变量会被提升到函数或全局作用域的顶部，但赋值不会被提升。
    
  - 重复声明：
    - 可以在同一作用域内重复声明同一个变量。

    function example() {
      console.log(a); // 输出: undefined
      var a = 10;
      console.log(a); // 输出: 10
    }
    example();

  2.  `let` 
  - 作用域：
    -  `let`  声明的变量具有块级作用域，只能在其所在的代码块内访问。
    
  - 提升：
    - 变量提升，但在声明之前不可访问（会导致  `ReferenceError` ）。
    
  - 重复声明：
    - 不能在同一作用域内重复声明同一个变量。
    {
        let b = 20;
        console.log(b); // 输出: 20
    }
    console.log(b); // 报错: ReferenceError: b is not defined

  3.  `const` 
  - 作用域：
    -  `const`  也具有块级作用域，与  `let`  相似。
    
  - 提升：
    - 同样会发生提升，但在声明之前不可访问。
    
  - 不可变性：
    - 一旦声明并赋值后，变量的值不可更改（但对于对象和数组，其内容是可变的）。
    
  - 重复声明：
    - 不能在同一作用域内重复声明同一个变量。

    const c = 30;
    console.log(c); // 输出: 30
    // c = 40; // 报错: TypeError: Assignment to constant variable.
    
    const obj = { name: 'Alice' };
    obj.name = 'Bob'; // 这是合法的
    console.log(obj.name); // 输出: Bob

总结:

| 特性       |  `var`                 |  `let`             |  `const`               |
|------------|----------------------|----------------------|----------------------|
| 作用域     | 函数作用域            | 块级作用域             | 块级作用域           |
| 提升       | 是                   | 是                   | 是                   |
| 重新声明   | 允许                 | 不允许                | 不允许               |
| 可变性     | 可变                 | 可变                 | 不可变（引用不变）   |

   -->
</head>
<body>
  
  <script>
    // 1.  `var` - 具有函数作用域，即变量在函数内部声明，函数外部无法访问。
    // console.log(a); // 报错输出: a is not defined
    function fooVar() {
      console.log("var", a); // 输出: undefined
      var a = 10;
      console.log("var", a); // 输出: 10
    }
    // console.log(a); // 报错输出: a is not defined
    fooVar();

    // 2.  `let` - 具有块级作用域，即变量在块级作用域内声明，块级作用域外无法访问。
    // 2.1
    // console.log(b); // 报错输出: b is not defined
    function fooLet() {
      console.log("let", b); // 报错输出: b is not defined
      if (true) {
        let b = 10;
        console.log("let", b); // 输出: 10
      }
      console.log("let", b); // 报错输出: b is not defined
    }
    // 2.2. 不能重复声明
    {
        let blet = 20;
        // var blet = 30; // 报错: Identifier 'blet' has already been declared
        // blet = 30; // 不报错
        // console.log(blet); // 输出: 30
        console.log("let", blet); // 输出: 20
    }
    // console.log(blet); // 报错: ReferenceError: blet is not defined

    // 3.  `const` - 具有块级作用域，且声明时必须初始化，且不可重新赋值。
    // 3.1
    // console.log(c); // 报错输出: c is not defined
    function fooConst() {
      // console.log(c); // 报错输出: c is not defined
      const c = 10;
      // c = 20; // 报错: Assignment to constant variable.
      console.log("const", c); // 输出: 10
    }
    // console.log(c); // 报错输出: c is not defined
    fooConst();

    // 3.2. 不能重复声明
    {
        const bconst = 50;
        // var bconst = 40; // 报错: Identifier 'bconst' has already been declared
        // bconst = 130; // 报错:  Assignment to constant variable.
        console.log("const", bconst); // 输出: 50
    }
    // console.log(bconst); // 报错: ReferenceError: bconst is not defined

  </script>
  
</body>
</html>